package com.suxin.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;
import java.util.Set;

/**
 * @Classname GroupChartServer
 * @Description [ TODO ]
 * @Author Tang
 * @Date 2020/12/29 9:34
 * @Created by ASUS
 */
public class GroupChatServer {

    private ServerSocketChannel serverSocketChannel;

    private Integer port;

    private Selector selector;

    public GroupChatServer(Integer port) {
        try {
            this.port = port;
            // 1.获取通道
            this.serverSocketChannel = ServerSocketChannel.open();
            this.serverSocketChannel.bind(new InetSocketAddress(this.port));
            // 2.服务端切换非阻塞
            this.serverSocketChannel.configureBlocking(false);
            // 3.获取选择器
            this.selector = Selector.open();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void run() throws Exception {
        // 4.将通道注册到选择器上面   指定事件     接收事件
        this.serverSocketChannel.register(this.selector, SelectionKey.OP_ACCEPT);
        // 阻塞等待连接事件
        while (this.selector.select() != 0) {
            // 获取连接事件
            Set<SelectionKey> selectionKeys = this.selector.selectedKeys();
            Iterator<SelectionKey> iterator = selectionKeys.iterator();
            while (iterator.hasNext()) {
                SelectionKey selectionKey = iterator.next();
                // 接收事件
                if (selectionKey.isAcceptable()) {
                    // 获取 SocketChannel
                    SocketChannel socketChannel = this.serverSocketChannel.accept();
                    socketChannel.configureBlocking(false);
                    // 注册可读事件
                    socketChannel.register(this.selector, SelectionKey.OP_READ);
//                    System.out.println("Accept hashCode--->" + socketChannel.hashCode());
                // 可读事件
                } else if (selectionKey.isReadable()) {
                    readAndForward(selectionKey);
                }else {
                    System.out.println("other...");
                }
                iterator.remove();
            }
        }
    }

    private void readAndForward(SelectionKey selectionKey){
        // 根据 selectionKey 获取 SocketChannel
        SocketChannel channel = (SocketChannel) selectionKey.channel();
        SocketAddress remoteAddress = null;
        // 读数据
        try {
            remoteAddress = channel.getRemoteAddress();
            ByteBuffer allocate = ByteBuffer.allocate(1024);
            int len;
            while ((len = channel.read(allocate)) != 0 && len != -1) {
                allocate.limit(len - 1);
                allocate.position(0);
                System.out.println("channel hashCode--->" + channel.hashCode() );
                System.out.println(
                        remoteAddress +
                                " client from msg：--->" + new String(allocate.array())
                );
                allocate.clear();
            }
            // 写回数据
            channel.write(ByteBuffer.wrap("hello,client!".getBytes()));
        } catch (Exception e) {
            // 连接断开，捕获异常
            selectionKey.cancel();
            try {
                channel.close();
            } catch (IOException ioException) {
                ioException.printStackTrace();
            }
            System.out.println(remoteAddress + " client lose...");
        }
    }

    public static void main(String[] args) throws Exception{
        GroupChatServer server = new GroupChatServer(9000);
        server.run();
    }

}